package com.cxyd.modules.wcs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cxyd.common.constant.RcsConstants;
import com.cxyd.common.constant.WcsConstants;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.StringUtils;
import com.cxyd.modules.api.dto.RcsResultHK;
import com.cxyd.modules.log.service.SysLogWorkService;
import com.cxyd.modules.wcs.dao.AgvCallbackHkDao;
import com.cxyd.modules.wcs.dto.AgvCallbackHkDTO;
import com.cxyd.modules.wcs.dto.PostTcpDTO;
import com.cxyd.modules.wcs.entity.*;
import com.cxyd.modules.wcs.service.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

@Service
public class AgvCallbackHkServiceImpl extends CrudServiceImpl<AgvCallbackHkDao, AgvCallbackHkEntity, AgvCallbackHkDTO> implements AgvCallbackHkService {
    @Resource
    private AgvTrkHkService hkService;
    @Resource
    private TrkService trkService;
    @Resource
    private PostWmsService postWmsService;
    @Resource
    private PostTcpService postTcpService;
    @Resource
    private StnMappingService stnMappingService;
    @Resource
    private SysLogWorkService logWorkService;

    @Override
    public QueryWrapper<AgvCallbackHkEntity> getWrapper(Map<String, Object> params) {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RcsResultHK callbackHandle(AgvCallbackHkDTO dto) {
        String reqCode = dto.getReqCode();
        String taskCode = dto.getTaskCode();
        String robotCode = dto.getRobotCode();
        String method = dto.getMethod();
//        当前站点信息
        String positionCode = dto.getCurrentPositionCode();
//        根据taskCode获取任务信息
        AgvTrkHkEntity task = hkService.getAgvTrkByTaskCode(taskCode);
        if (task == null) {
            return new RcsResultHK().error(reqCode, "任务不存在或已被取消!");
        }
//        记录车号
        task.setAgvCode(robotCode);
//        不同的method调用不同的处理逻辑
        if (RcsConstants.HK_METHOD_START.equals(method)) {
//            1.任务开始(更新任务当前状态0-初始 1-任务下发 2-任务开始 3-搬送中 4-任务完成 9-任务取消)
            agvTrkStart(task, positionCode);
        } else if (RcsConstants.HK_METHOD_OUTBIN.equals(method)) {
//            2.走出储位(可认为是下架)
            agvTrkOutbin(task, positionCode);
        } else if (RcsConstants.HK_METHOD_LOAD.equals(method)) {
//            3.AGV-LOAD申请(请求上料)
            agvTrkApplyLoad(task, positionCode);
        } else if (RcsConstants.HK_METHOD_UNLOAD.equals(method)) {
//            4.AGV-UNLOAD申请(请求下料)
            agvTrkApplyUnload(task, positionCode);
        } else if (RcsConstants.HK_METHOD_ARRIVED.equals(method)) {
//            5.AGV-到达光栅位置
            agvTrkApplyArrived(task, positionCode);
        } else if (RcsConstants.HK_METHOD_START_UNLOAD.equals(method)) {
//            6.AGV-下料申请（顶起料架）
            agvTrkApplyStartUnload(task, positionCode);
        } else if (RcsConstants.HK_METHOD_LOAD_DONE.equals(method)) {
//            6.AGV-下料申请（放下料架）
            agvTrkApplyLoadDone(task, positionCode);
        } else if (RcsConstants.HK_METHOD_LEAVE.equals(method)) {
//            7.AGV-顶起料架后申请离开
            agvTrkApplyLeave(task, positionCode);
        } else if (RcsConstants.HK_METHOD_FINISH.equals(method)) {
//            7.AGV-顶起料架后申请离开
            agvTrkFinished(task, positionCode);
        } else if (RcsConstants.HK_METHOD_END.equals(method)) {
//            7.AGV-顶起料架后申请离开
            agvTrkEnd(task, positionCode);
        } else {

        }
        return new RcsResultHK().success(reqCode);
    }

    /***
     * 任务开始(步骤1)
     * @param task
     */
    private void agvTrkStart(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-START]任务开始-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkStart";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + task.getAgvCode() + "]准备从站点[" + positionCode + "]搬送料箱[" + task.getCtnrCode() + "]!method为[start]";
//        start时并未执行该任务,只是说CTU接到有任务而已
        task.setStatus(RcsConstants.HK_STATUS_START);
        task.setCurrentPositionCode(positionCode);
        task.setData("RCS接收任务后开始执行!method-[start]");
        task.setUpdater(WcsConstants.WCS_USER_ID);
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        找到对应[wcs_trk]任务进行更新
        TrkEntity trkEntity = trkService.selectById(task.getTrkId());
        if (trkEntity == null) {
            return;
        }
        trkEntity.setComments(pMsg);
        trkEntity.setUpdater(WcsConstants.WCS_USER_ID);
        trkEntity.setUpdateDate(new Date());
        trkService.updateById(trkEntity);
//        以料箱维度记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 走出储位（一般为出库下架）
     * @param task
     */
    private void agvTrkOutbin(AgvTrkHkEntity task, String positionCode) {
//        通知wms料箱已下架等
        String workName = "[流程-2]小车取放请求";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkOutbin";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + task.getAgvCode() + "]将缓存区[" + positionCode + "]料架取出!";
//        释放当前位置的缓存货位
        StnMappingEntity curStn = stnMappingService.getStnByNo(positionCode);
        curStn.setStatus(0);
        curStn.setContNo("");
        curStn.setContType("");
        curStn.setIsFull("");
        curStn.setComments(pMsg);
        curStn.setUpdateDate(new Date());
        stnMappingService.updateById(curStn);

//        更新任务状态
        task.setStatus(RcsConstants.HK_STATUS_TAKE); //任务状态
        task.setData("AGV取出料架!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);

        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * AGV-LOAD申请(完成)
     * @param task
     */
    private void agvTrkApplyLoad(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-LOAD]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyLoad";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[LoadRequest]申请!";
//        获取当前站点对应的机台编号
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-样式为[$$LoadRequest,Target:L4_ST36_01%%]
        String postMsg = "$$LoadRequest,Target:" + stnByNo.getTargetNo() + "%%";
        PostTcpDTO postDTO = new PostTcpDTO();
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("LoadRequest");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(postMsg);
        postTcpService.save(postDTO);

//        更新任务状态
        task.setStatus(RcsConstants.HK_STATUS_LOAD); //任务状态
        task.setData("$$LoadRequest!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * AGV-UNLOAD申请
     * @param task
     */
    private void agvTrkApplyUnload(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-UNLOAD]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyUnload";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[UnloadRequest]申请!";
//        根据当前位置获取一下站台对应的站点
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-示例[$$UnloadRequest,TypeNo:1111111111,Typevar:'',Cnt:0,Target:L4_ST36_01%%]
        String postMsg = "$$UnloadRequest,TypeNo:1111111111,TypeVar:0,Cnt:100,Target:" + stnByNo.getTargetNo() + "%%";
        PostTcpDTO postDTO = new PostTcpDTO();
//        更新任务状态
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("UnloadRequest");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(postMsg);
        postTcpService.save(postDTO);
        task.setStatus(RcsConstants.HK_STATUS_UNLOAD); //任务状态
        task.setData("UnloadRequest!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * CTU取放申请
     * @param task
     */
    private void agvTrkApplyArrived(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-ARRIVED]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyArrived";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[Arrived]申请!";
//        根据当前位置获取一下站台对应的站点
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-示例[$$Arrived%%]
        PostTcpDTO postDTO = new PostTcpDTO();
//        更新任务状态
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("Arrived");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(WcsConstants.TCP_MSG_ARRIVED);
        postTcpService.save(postDTO);
        task.setStatus(RcsConstants.HK_STATUS_ARRIVED); //任务状态
        task.setData("Arrived!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    private void agvTrkApplyStartUnload(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-START-UNLOAD]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyStartUnload";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号小车在[" + positionCode + "]申请[StartUnloading]";
        //        根据当前位置获取一下站台对应的站点
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-示例[$$Arrived%%]
        PostTcpDTO postDTO = new PostTcpDTO();
//        更新任务状态
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("StartUnloading");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(WcsConstants.TCP_MSG_START_UNLOAD);
        postTcpService.save(postDTO);

        task.setStatus(RcsConstants.HK_STATUS_START_UNLOAD); //任务状态
        task.setData("StartUnload!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    private void agvTrkApplyLoadDone(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-LOAD-DONE]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyLoadDone";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号小车在[" + positionCode + "]申请[LoadDone]";
        //        根据当前位置获取一下站台对应的站点
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        更新机台状态(上料则机台被占用)
        stnByNo.setStatus(2);
        stnByNo.setContNo(task.getPodCode());
        stnByNo.setContType(task.getPodType());
        stnByNo.setIsFull("false");
        stnByNo.setComments(pMsg);
        stnByNo.setUpdateDate(new Date());
        stnMappingService.updateById(stnByNo);

//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-示例[$$LoadDone%%]
        PostTcpDTO postDTO = new PostTcpDTO();
//        更新任务状态
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("LoadDone");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(WcsConstants.TCP_MSG_LOAD_DONE);
        postTcpService.save(postDTO);

        task.setStatus(RcsConstants.HK_STATUS_LOAD_DONE); //任务状态
        task.setData("LoadDone!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    private void agvTrkApplyLeave(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-LEAVE]放货-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyLeave";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号小车在[" + positionCode + "]申请[LeaveRequest]";
        //        根据当前位置获取一下站台对应的站点
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        更新机台状态(下料则是释放机台状态)
        stnByNo.setStatus(0);
        stnByNo.setContNo("");
        stnByNo.setContType("");
        stnByNo.setIsFull("");
        stnByNo.setComments(pMsg);
        stnByNo.setUpdateDate(new Date());
        stnMappingService.updateById(stnByNo);

//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-示例[$$LoadDone%%]
        PostTcpDTO postDTO = new PostTcpDTO();
//        更新任务状态
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("LeaveRequest");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(WcsConstants.TCP_MSG_LEAVE_REQUEST);
        postTcpService.save(postDTO);

        task.setStatus(RcsConstants.HK_STATUS_LEAVE); //任务状态
        task.setData("LeaveRequest!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    private void agvTrkFinished(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-FINISHED]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkFinished";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "[" + task.getAgvCode() + "]号小车在[" + positionCode + "]申请[Finished]";
        //        根据当前位置获取一下站台对应的站点
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo == null) {
            return;
        }
//        与机台进行安全交互(向wcs_post_tcp表中写入数据)-示例[$$LoadDone%%]
        PostTcpDTO postDTO = new PostTcpDTO();
//        更新任务状态
        postDTO.setPostSt(WcsConstants.POST_STATUS_START);
        postDTO.setNoticeType("Finished");
        postDTO.setCurPos(positionCode);
        postDTO.setDvcNo(stnByNo.getDvcNo());
        postDTO.setContNo(task.getCtnrCode());
        postDTO.setTaskCode(task.getTaskCode());
        postDTO.setTaskTyp(task.getTaskTyp());
        postDTO.setTarget(stnByNo.getTargetNo());
        postDTO.setPostMsg(WcsConstants.TCP_MSG_FINISHED);
        postTcpService.save(postDTO);

        task.setStatus(RcsConstants.HK_STATUS_FINISHED); //任务状态
        task.setData("Finished!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 任务结束(将对应agv搬送任务完成并转移历史)
     * @param task
     */
    private void agvTrkEnd(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-END]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkEnd";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + task.getAgvCode() + "]搬送料箱[" + task.getPodCode() + "]到达站点[" + positionCode + "],任务完成!";

//      获取[wcs_trk]信息
        task.setStatus(RcsConstants.HK_STATUS_END); //任务完成
        task.setData("End!");
        task.setCurrentPositionCode(positionCode);
        task.setUpdateDate(new Date());
        hkService.updateById(task);
        TrkEntity trkEntity = trkService.selectById(task.getTrkId());
        if (trkEntity == null) {
            return;
        }

//        根据当前位置获取一下站台对应的站点（任务结束一定是将料架上到目标位置了）
        StnMappingEntity stnByNo = stnMappingService.getStnByNo(positionCode);
        if (stnByNo != null) {
            stnByNo.setStatus(2);
            stnByNo.setContNo(task.getPodCode());
            stnByNo.setContType(task.getPodType());
            stnByNo.setIsFull(trkEntity.getIsFull());
            stnByNo.setComments(pMsg);
            stnByNo.setUpdateDate(new Date());
            stnMappingService.updateById(stnByNo);
        }

        trkEntity.setTrkSt(WcsConstants.TRK_STATUS_DONE);
        trkEntity.setComments(pMsg);
        trkEntity.setCurPos(positionCode);
        trkEntity.setUpdater(WcsConstants.WCS_USER_ID);
        trkEntity.setUpdateDate(new Date());
        trkService.updateById(trkEntity);
//        判断是否有同组号且设备编号为[WAIT_AGV]的任务,如果有则将其设备编号更新为[HK_AGV]
        if (!StringUtils.isBlank(trkEntity.getGroupNo())) {
            TrkEntity brotherTrk = trkService.selectByGroupNo(trkEntity.getGroupNo());
            if (brotherTrk != null) {
                brotherTrk.setDvcNo("HK_AGV");
                brotherTrk.setComments("前置任务完成,后置任务开始执行!");
                brotherTrk.setUpdateDate(new Date());
                trkService.updateById(brotherTrk);
            }
        }
//        如果创建用户=MES则需要上报MES
        if (trkEntity.getCreator().equals(WcsConstants.MES_USER_ID)) {
            PostWmsEntity postWms = new PostWmsEntity();
            postWms.setRequestPk(trkEntity.getRequestPk());
            postWms.setContNo(trkEntity.getContNo());
            postWms.setCurPos(trkEntity.getToPos());
//        类型为[完成]
            postWms.setNoticeType(WcsConstants.POST_TYPE_DONE);
            postWms.setCode(pCode);
            postWms.setResult(pMsg);
            postWms.setPostSt(WcsConstants.POST_STATUS_START);
            postWms.setCreator(WcsConstants.WCS_USER_ID);
            postWms.setUpdateDate(new Date());
            postWmsService.insert(postWms);
        } else {
//            内部MCS自己生成的任务直接转移历史即可
            trkService.deleteById(trkEntity.getTrkId());
        }
//        将AGV任务转移历史
        hkService.updateAgvTrkByContNo(task.getPodCode());
//        将POST_TCP数据也进行转移
        postTcpService.backupPostTcpByTaskCode(task.getTaskCode());
        logWorkService.workLogging(workName, task.getTaskCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }
}
